/**
 * 
 */
package constraints;

import info.Constant;
import infomanager.GroupManager;
import infomanager.SubjectManager;

import java.util.ArrayList;
import java.util.Arrays;

import evolution.Gene;

/**
 * @author vtkhanh
 * 
 */
public class SoftConstraint {
    public static final short MAX_SEQUENTIAL_PERIOD = 3;
    public static final int SEQUENTIAL_PERIODS_COST = 10;
    public static final int PERIODS_OF_SUBJECT_IN_DAY_COST = 10;

    /**
     * Check if the number of sequential periods is too many
     * 
     * @param genes
     * @param register
     * @return
     */
    public static ArrayList<Gene> checkSequentialPeriods(ArrayList<Gene> genes,
	    short[][] register) {
	int groupNum = GroupManager.getGroups().length;
	ArrayList<Gene> modifiedGenes = new ArrayList<Gene>();
	// store number of sequential period of groups
	int count;
	short timeslot;

	for (short groupId = 0; groupId < groupNum; groupId++) {
	    timeslot = 0;
	    while (timeslot < Constant.TIMESLOT_NUM) {
		count = 0;
		while ((timeslot < Constant.TIMESLOT_NUM)
			&& (register[groupId][timeslot] == 0)) {
		    timeslot++;
		}
		while ((timeslot < Constant.TIMESLOT_NUM)
			&& (register[groupId][timeslot] == 1)) {
		    count++;
		    timeslot++;
		}
		if (count > MAX_SEQUENTIAL_PERIOD) {
		    detectModifiedGenes(genes, modifiedGenes, groupId,
			    timeslot, count, SEQUENTIAL_PERIODS_COST,
			    "SEQUENTIAL_PERIOD");
		}
	    }
	}

	return modifiedGenes;
    }

    private static void detectModifiedGenes(ArrayList<Gene> genes,
	    ArrayList<Gene> modifiedGenes, short groupId, short timeslot,
	    int count, int cost, String costType) {
	int t;
	int id;
	for (Gene gene : genes) {
	    t = gene.getTimeslot();
	    id = gene.getCourse().getGroup().getGroupId();
	    if ((id == groupId) && (t < timeslot) && (timeslot - t <= count)) {
		modifiedGenes.add(gene);
		gene.addCost(cost);
		gene.setCostType(costType);
	    }
	}
    }

    /**
     * Check if the periods of one subject is overloaded in a day
     * 
     * @param genes
     * @return
     */
    public static ArrayList<Gene> checkPeriodsPerSubjectInOneDay(
	    ArrayList<Gene> genes) {
	ArrayList<Gene> modifiedGenes = new ArrayList<Gene>();
	int groupNum = GroupManager.getGroups().length;
	boolean[][] subjects = new boolean[groupNum][SubjectManager.getSubjects().length];

	for (short day = 0; day < Constant.DAY_NUM; day++) {
	    for (int i = 0; i < groupNum; i++) {
		Arrays.fill(subjects[i], false);
	    }
	    for (Gene gene : genes) {
		if ((gene.getTimeslot() / Constant.PERIODS_IN_DAY) == day) {
		    int groupId = gene.getCourse().getGroup().getGroupId();
		    int subjectId = gene.getCourse().getSubject().getSubjectId();

		    if (subjects[groupId][subjectId]) {
			if (!modifiedGenes.contains(gene)) {
			    detectModifiedGenes(genes, modifiedGenes,
				    groupId, subjectId, day,
				    PERIODS_OF_SUBJECT_IN_DAY_COST,
				    "PERIODS_OF_SUBJECT_IN_DAY");
			}
		    } else {
			subjects[groupId][subjectId] = true;
		    }
		}
	    }
	}
	return modifiedGenes;
    }

    private static void detectModifiedGenes(ArrayList<Gene> genes,
	    ArrayList<Gene> modifiedGenes, int groupId, int subjectId,
	    short day, int cost, String costType) {
	for (Gene gene : genes) {
	    if (gene.getTimeslot() / Constant.PERIODS_IN_DAY == day) {
		if ((gene.getCourse().getGroup().getGroupId() == groupId)
			&& (gene.getCourse().getSubject().getSubjectId() == subjectId)) {
		    modifiedGenes.add(gene);
		    gene.addCost(cost);
		    gene.setCostType(costType);
		}
	    }
	}
    }

}
